#include "FileUploadTask.h"
#include "TcpConnection.h"
#include "MessageCodec.h"
#include "protocol.h"
#include "block_log.h"
#include "ConnectPool.h"
#include "Connect.h"
#include <fstream>
#include <thread>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <chrono>
#include <algorithm>
#include <map>
#include <mutex>

// 上传会话信息
struct UploadSession {
    uint64_t user_id;
    std::string file_name;
    std::string file_type;
    uint64_t file_size;
    std::string temp_path;      // 临时文件路径
    std::string final_path;     // 最终文件路径
    uint64_t received_size;     // 已接收大小
    std::chrono::steady_clock::time_point create_time;
};

// 全局上传会话管理（线程安全）
static std::map<std::string, UploadSession> g_upload_sessions;
static std::mutex g_sessions_mutex;

FileUploadTask::FileUploadTask(TcpConnection* conn, const std::string& jsonBody)
    : m_conn(conn), m_jsonBody(jsonBody)
{
}

FileUploadTask::~FileUploadTask()
{
}

void FileUploadTask::work(void* arg)
{
    Debug("FileUploadTask 开始执行（初始化上传），线程 ID: %llu", std::this_thread::get_id());
    
    // 步骤 1: 解析文件上传请求
    auto requestOpt = MessageCodec::fileUploadRequestFromJson(m_jsonBody);
    if (!requestOpt) {
        Debug("文件上传请求 JSON 解析失败");
        
        FileUploadResponse errorRes;
        errorRes.success = false;
        errorRes.message = "请求格式错误";
        errorRes.upload_id = "";
        errorRes.file_path = "";
        errorRes.file_url = "";
        
        auto responseData = MessageCodec::encode(errorRes);
        m_conn->sendResponseAsync(responseData);
        return;
    }
    
    FileUploadRequest req = *requestOpt;
    Debug("初始化文件上传 - 文件名: %s, 类型: %s, 大小: %llu", 
          req.file_name.c_str(), req.file_type.c_str(), req.file_size);
    
    // 步骤 2: 验证文件类型
    if (!validateFileType(req.file_name, req.file_type)) {
        Debug("文件类型不支持: %s", req.file_name.c_str());
        
        FileUploadResponse errorRes;
        errorRes.success = false;
        errorRes.message = "文件类型不支持";
        errorRes.upload_id = "";
        errorRes.file_path = "";
        errorRes.file_url = "";
        
        auto responseData = MessageCodec::encode(errorRes);
        m_conn->sendResponseAsync(responseData);
        return;
    }
    
    // 步骤 3: 检查文件大小限制（10MB）
    const uint64_t MAX_FILE_SIZE = 10 * 1024 * 1024;
    if (req.file_size > MAX_FILE_SIZE) {
        Debug("文件过大: %llu 字节", req.file_size);
        
        FileUploadResponse errorRes;
        errorRes.success = false;
        errorRes.message = "文件大小超过限制（最大10MB）";
        errorRes.upload_id = "";
        errorRes.file_path = "";
        errorRes.file_url = "";
        
        auto responseData = MessageCodec::encode(errorRes);
        m_conn->sendResponseAsync(responseData);
        return;
    }
    
    // 步骤 4: 获取用户ID
    uint64_t user_id = m_conn->getUserId();
    if (user_id == 0) {
        Debug("用户未登录，无法上传文件");
        
        FileUploadResponse errorRes;
        errorRes.success = false;
        errorRes.message = "用户未登录";
        errorRes.upload_id = "";
        errorRes.file_path = "";
        errorRes.file_url = "";
        
        auto responseData = MessageCodec::encode(errorRes);
        m_conn->sendResponseAsync(responseData);
        return;
    }
    
    // 步骤 5: 生成上传会话ID
    std::string upload_id = generateUploadId();
    
    // 步骤 6: 生成临时文件路径和最终路径
    std::string temp_dir = "uploads/temp";
    std::string temp_path = temp_dir + "/" + upload_id;
    std::string final_path = generateFilePath(req.file_type, req.file_name, user_id);
    std::string save_dir = getSaveDirectory(req.file_type);
    
    // 步骤 7: 创建目录
    struct stat st;
    if (stat(temp_dir.c_str(), &st) != 0) {
        std::string mkdir_cmd = "mkdir -p " + temp_dir;
        system(mkdir_cmd.c_str());
    }
    if (stat(save_dir.c_str(), &st) != 0) {
        std::string mkdir_cmd = "mkdir -p " + save_dir;
        system(mkdir_cmd.c_str());
    }
    
    // 步骤 8: 创建空的临时文件
    std::ofstream temp_file(temp_path, std::ios::binary);
    if (!temp_file.is_open()) {
        Debug("无法创建临时文件: %s", temp_path.c_str());
        
        FileUploadResponse errorRes;
        errorRes.success = false;
        errorRes.message = "服务器内部错误";
        errorRes.upload_id = "";
        errorRes.file_path = "";
        errorRes.file_url = "";
        
        auto responseData = MessageCodec::encode(errorRes);
        m_conn->sendResponseAsync(responseData);
        return;
    }
    temp_file.close();
    
    // 步骤 9: 创建上传会话
    UploadSession session;
    session.user_id = user_id;
    session.file_name = req.file_name;
    session.file_type = req.file_type;
    session.file_size = req.file_size;
    session.temp_path = temp_path;
    session.final_path = final_path;
    session.received_size = 0;
    session.create_time = std::chrono::steady_clock::now();
    
    {
        std::lock_guard<std::mutex> lock(g_sessions_mutex);
        g_upload_sessions[upload_id] = session;
    }
    
    Debug("上传会话已创建 - upload_id: %s, 临时文件: %s", upload_id.c_str(), temp_path.c_str());
    
    // 步骤 10: 返回成功响应
    FileUploadResponse response;
    response.success = true;
    response.message = "准备接收文件数据";
    response.upload_id = upload_id;
    response.file_path = "";
    response.file_url = "";
    
    auto responseData = MessageCodec::encode(response);
    m_conn->sendResponseAsync(responseData);
    
    Debug("FileUploadTask 初始化完成");
}

// 静态方法：处理文件数据块
bool FileUploadTask::handleFileChunk(TcpConnection* conn, const std::string& jsonBody)
{
    Debug("处理文件数据块");
    
    // 1. 解析数据块
    auto dataOpt = MessageCodec::fileUploadDataFromJson(jsonBody);
    if (!dataOpt) {
        Debug("文件数据块解析失败");
        return false;
    }
    
    FileUploadData data = *dataOpt;
    Debug("接收数据块 - upload_id: %s, chunk: %u, is_last: %d", 
          data.upload_id.c_str(), data.chunk_index, data.is_last);
    
    // 2. 查找上传会话
    UploadSession session;
    {
        std::lock_guard<std::mutex> lock(g_sessions_mutex);
        auto it = g_upload_sessions.find(data.upload_id);
        if (it == g_upload_sessions.end()) {
            Debug("上传会话不存在: %s", data.upload_id.c_str());
            return false;
        }
        session = it->second;
    }
    
    // 3. Base64 解码
    std::string binary_data = base64Decode(data.data);
    if (binary_data.empty()) {
        Debug("Base64 解码失败");
        return false;
    }
    
    // 4. 追加写入临时文件
    std::ofstream file(session.temp_path, std::ios::binary | std::ios::app);
    if (!file.is_open()) {
        Debug("无法打开临时文件: %s", session.temp_path.c_str());
        return false;
    }
    
    file.write(binary_data.data(), binary_data.size());
    file.close();
    
    // 5. 更新已接收大小
    session.received_size += binary_data.size();
    
    {
        std::lock_guard<std::mutex> lock(g_sessions_mutex);
        g_upload_sessions[data.upload_id].received_size = session.received_size;
    }
    
    Debug("数据块写入成功，已接收: %llu / %llu 字节", session.received_size, session.file_size);
    
    // 6. 如果是最后一块，完成上传
    if (data.is_last) {
        Debug("接收到最后一块，开始完成上传");
        
        // 移动文件到最终位置
        std::string mv_cmd = "mv " + session.temp_path + " " + session.final_path;
        int ret = system(mv_cmd.c_str());
        
        if (ret != 0) {
            Debug("移动文件失败");
            remove(session.temp_path.c_str());
            
            {
                std::lock_guard<std::mutex> lock(g_sessions_mutex);
                g_upload_sessions.erase(data.upload_id);
            }
            
            FileUploadResponse errorRes;
            errorRes.success = false;
            errorRes.message = "文件保存失败";
            errorRes.upload_id = data.upload_id;
            errorRes.file_path = "";
            errorRes.file_url = "";
            
            auto responseData = MessageCodec::encode(errorRes);
            conn->sendResponseAsync(responseData);
            return false;
        }
        
        Debug("文件上传完成: %s", session.final_path.c_str());
        
        // 如果是头像，更新数据库
        if (session.file_type == "avatar") {
            FileUploadTask task(conn, "");
            if (!task.updateUserAvatar(session.user_id, session.final_path)) {
                Debug("更新用户头像失败");
            }
        }
        
        // 发送完成响应
        FileUploadResponse response;
        response.success = true;
        response.message = "文件上传成功";
        response.upload_id = data.upload_id;
        response.file_path = session.final_path;
        response.file_url = "/" + session.final_path;
        
        auto responseData = MessageCodec::encode(response);
        conn->sendResponseAsync(responseData);
        
        // 删除会话
        {
            std::lock_guard<std::mutex> lock(g_sessions_mutex);
            g_upload_sessions.erase(data.upload_id);
        }
    }
    
    return true;
}

std::string FileUploadTask::generateUploadId()
{
    auto now = std::chrono::system_clock::now();
    auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
        now.time_since_epoch()).count();
    
    std::stringstream ss;
    ss << "upload_" << m_conn->getUserId() << "_" << timestamp;
    return ss.str();
}

bool FileUploadTask::validateFileType(const std::string& file_name, const std::string& file_type)
{
    std::string extension = "";
    size_t dot_pos = file_name.find_last_of('.');
    if (dot_pos != std::string::npos) {
        extension = file_name.substr(dot_pos);
        std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
    }
    
    Debug("验证文件类型 - 文件名: %s, 扩展名: %s, file_type: %s", 
          file_name.c_str(), extension.c_str(), file_type.c_str());
    
    if (file_type == "avatar") {
        if (extension == ".jpg" || extension == ".jpeg" || 
            extension == ".png" || extension == ".gif" || extension == ".webp") {
            return true;
        }
        Debug("不支持的头像格式: %s", extension.c_str());
        return false;
    }
    else if (file_type == "image") {
        if (extension == ".jpg" || extension == ".jpeg" || 
            extension == ".png" || extension == ".gif" || 
            extension == ".bmp" || extension == ".webp") {
            return true;
        }
        return false;
    }
    else if (file_type == "document") {
        if (extension == ".pdf" || extension == ".doc" || 
            extension == ".docx" || extension == ".txt" || 
            extension == ".xls" || extension == ".xlsx") {
            return true;
        }
        return false;
    }
    
    return false;
}

std::string FileUploadTask::getSaveDirectory(const std::string& file_type)
{
    if (file_type == "avatar") {
        return "uploads/avatars";
    } else if (file_type == "image") {
        return "uploads/images";
    } else if (file_type == "document") {
        return "uploads/documents";
    }
    return "uploads/others";
}

std::string FileUploadTask::generateFilePath(const std::string& file_type, 
                                            const std::string& file_name, 
                                            uint64_t user_id)
{
    std::string dir = getSaveDirectory(file_type);
    
    std::string extension = "";
    size_t dot_pos = file_name.find_last_of('.');
    if (dot_pos != std::string::npos) {
        extension = file_name.substr(dot_pos);
    }
    
    auto now = std::chrono::system_clock::now();
    auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
        now.time_since_epoch()).count();
    
    std::stringstream ss;
    ss << dir << "/" << user_id << "_" << timestamp << extension;
    return ss.str();
}

std::string FileUploadTask::base64Decode(const std::string& encoded)
{
    static const std::string base64_chars = 
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
        "0123456789+/";
    
    auto is_base64 = [](unsigned char c) {
        return (isalnum(c) || (c == '+') || (c == '/'));
    };
    
    size_t in_len = encoded.size();
    int i = 0;
    int j = 0;
    int in_ = 0;
    unsigned char char_array_4[4], char_array_3[3];
    std::string ret;

    while (in_len-- && (encoded[in_] != '=') && is_base64(encoded[in_])) {
        char_array_4[i++] = encoded[in_]; in_++;
        if (i == 4) {
            for (i = 0; i < 4; i++)
                char_array_4[i] = base64_chars.find(char_array_4[i]);

            char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
            char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
            char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

            for (i = 0; (i < 3); i++)
                ret += char_array_3[i];
            i = 0;
        }
    }

    if (i) {
        for (j = i; j < 4; j++)
            char_array_4[j] = 0;

        for (j = 0; j < 4; j++)
            char_array_4[j] = base64_chars.find(char_array_4[j]);

        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

        for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
    }

    return ret;
}

bool FileUploadTask::saveFileChunk(const std::string& upload_id, 
                                  const std::string& chunk_data, 
                                  bool is_last)
{
    // 这个方法已被 handleFileChunk 替代
    return false;
}

bool FileUploadTask::updateUserAvatar(uint64_t user_id, const std::string& avatar_path)
{
    try {
        auto connPool = ConnectionPool::getConnectionPool();
        auto dbConn = connPool->getConnection();
        
        if (!dbConn) {
            Debug("获取数据库连接失败");
            return false;
        }
        
        sql::Connection* conn = dbConn->getConnection();
        
        std::unique_ptr<sql::PreparedStatement> pstmt(
            conn->prepareStatement(
                "UPDATE users SET avatar_url = ? WHERE user_id = ?"
            )
        );
        
        pstmt->setString(1, avatar_path);
        pstmt->setUInt64(2, user_id);
        
        int rows = pstmt->executeUpdate();
        
        if (rows > 0) {
            Debug("用户 %llu 头像更新成功：%s", user_id, avatar_path.c_str());
            return true;
        } else {
            Debug("用户 %llu 不存在，头像更新失败", user_id);
            return false;
        }
        
    } catch (const SQLException& e) {
        Debug("数据库更新异常: %s (错误码: %d)", e.what(), e.getErrorCode());
        return false;
    }
}
